<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RocketMQ消息异常处理全指南</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            line-height: 1.8;
            color: #333;
        }
        h1, h2, h3, h4, h5, h6 {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
            color: #222;
        }
        .hero {
            background: linear-gradient(135deg, #1e3a8a 0%, #2563eb 100%);
        }
        .code-block {
            background-color: #f8fafc;
            border-left: 4px solid #3b82f6;
        }
        .card {
            transition: all 0.3s ease;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
        }
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
        }
        .icon-circle {
            width: 60px;
            height: 60px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-bottom: 1rem;
        }
        .section-divider {
            height: 1px;
            background: linear-gradient(90deg, rgba(59,130,246,0.1) 0%, rgba(59,130,246,0.5) 50%, rgba(59,130,246,0.1) 100%);
            margin: 3rem 0;
        }
        .footer {
            background-color: #1e293b;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <section class="hero text-white py-20 px-4 md:px-0">
        <div class="container mx-auto max-w-5xl text-center">
            <div class="flex justify-center mb-6">
                <div class="bg-white/20 rounded-full p-3">
                    <i class="fas fa-rocket text-3xl"></i>
                </div>
            </div>
            <h1 class="text-4xl md:text-5xl font-bold mb-4">RocketMQ消息异常处理全指南</h1>
            <p class="text-xl md:text-2xl opacity-90 mb-8">构建高可靠的分布式消息系统</p>
            <div class="max-w-3xl mx-auto">
                <p class="text-lg opacity-90 mb-8">在分布式消息系统中，消息异常是不可避免的问题。本指南将全面介绍RocketMQ如何处理发送失败和消费异常，确保消息的可靠传递。</p>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto max-w-5xl px-4 md:px-0 py-12">
        <!-- Intro Section -->
        <section class="mb-16">
            <div class="bg-white rounded-xl shadow-sm p-8">
                <h2 class="text-3xl font-bold mb-6 text-blue-800">消息异常处理的重要性</h2>
                <p class="text-lg mb-6">在分布式系统中，网络分区、节点故障、资源不足等问题会导致消息发送和消费失败。RocketMQ提供了完善的异常处理机制，包括自动重试、故障转移、死信队列等，确保消息最终能被正确处理。</p>
                
                <div class="grid md:grid-cols-3 gap-6 mt-8">
                    <div class="card bg-white p-6 rounded-lg border border-gray-100">
                        <div class="icon-circle bg-blue-100 text-blue-600 mx-auto">
                            <i class="fas fa-sync-alt text-2xl"></i>
                        </div>
                        <h3 class="text-xl font-semibold text-center mb-3">自动重试</h3>
                        <p class="text-gray-600 text-center">内置多层次重试机制，包括同步重试、异步重试和业务层重试</p>
                    </div>
                    <div class="card bg-white p-6 rounded-lg border border-gray-100">
                        <div class="icon-circle bg-green-100 text-green-600 mx-auto">
                            <i class="fas fa-exchange-alt text-2xl"></i>
                        </div>
                        <h3 class="text-xl font-semibold text-center mb-3">故障转移</h3>
                        <p class="text-gray-600 text-center">Broker和NameServer的自动故障转移，保证服务高可用</p>
                    </div>
                    <div class="card bg-white p-6 rounded-lg border border-gray-100">
                        <div class="icon-circle bg-purple-100 text-purple-600 mx-auto">
                            <i class="fas fa-exclamation-triangle text-2xl"></i>
                        </div>
                        <h3 class="text-xl font-semibold text-center mb-3">死信队列</h3>
                        <p class="text-gray-600 text-center">超过重试次数的消息进入死信队列，避免消息丢失</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Message Send Failure Section -->
        <section class="mb-16">
            <div class="bg-white rounded-xl shadow-sm p-8">
                <div class="flex items-center mb-6">
                    <div class="w-2 h-10 bg-blue-600 rounded-full mr-4"></div>
                    <h2 class="text-3xl font-bold text-blue-800">消息发送失败的处理策略</h2>
                </div>
                
                <p class="text-lg mb-8">在分布式消息系统中，消息发送失败是不可避免的问题。RocketMQ提供了多种机制来处理消息发送失败的情况，确保消息的可靠传递。</p>
                
                <div class="grid md:grid-cols-2 gap-8">
                    <div>
                        <h3 class="text-2xl font-semibold mb-4 text-gray-800">发送失败的常见原因</h3>
                        <ul class="space-y-3">
                            <li class="flex items-start">
                                <i class="fas fa-network-wired text-blue-500 mt-1 mr-3"></i>
                                <span><strong>网络异常：</strong>连接中断、网络拥塞、DNS解析失败</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-server text-blue-500 mt-1 mr-3"></i>
                                <span><strong>Broker异常：</strong>服务不可用、磁盘满、负载过高</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-laptop-code text-blue-500 mt-1 mr-3"></i>
                                <span><strong>客户端异常：</strong>配置错误、资源不足、权限不足</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-envelope text-blue-500 mt-1 mr-3"></i>
                                <span><strong>消息异常：</strong>消息体过大、格式错误、属性不符</span>
                            </li>
                        </ul>
                    </div>
                    <div>
                        <h3 class="text-2xl font-semibold mb-4 text-gray-800">内置重试机制</h3>
                        <div class="bg-gray-50 p-4 rounded-lg mb-4">
                            <div class="flex items-center text-sm text-gray-500 mb-2">
                                <i class="fas fa-code mr-2"></i>
                                <span>同步发送重试</span>
                            </div>
                            <div class="code-block p-4 rounded-md">
                                <code class="text-sm">producer.setRetryTimesWhenSendFailed(3); // 设置重试3次</code>
                            </div>
                        </div>
                        <div class="bg-gray-50 p-4 rounded-lg">
                            <div class="flex items-center text-sm text-gray-500 mb-2">
                                <i class="fas fa-code mr-2"></i>
                                <span>异步发送重试</span>
                            </div>
                            <div class="code-block p-4 rounded-md">
                                <code class="text-sm">producer.setRetryTimesWhenSendAsyncFailed(2); // 设置异步发送重试2次</code>
                            </div>
                        </div>
                    </div>
                </div>
                
                <div class="mt-10">
                    <h3 class="text-2xl font-semibold mb-4 text-gray-800">故障转移机制</h3>
                    <div class="grid md:grid-cols-2 gap-6">
                        <div class="bg-gray-50 p-5 rounded-lg">
                            <h4 class="font-medium text-lg mb-3 text-blue-700">Broker故障转移</h4>
                            <p class="mb-3">当主Broker不可用时，自动切换到从Broker，通过延迟容错智能规避高延迟Broker。</p>
                            <div class="code-block p-4 rounded-md">
                                <code class="text-sm">producer.setSendLatencyFaultEnable(true);</code>
                            </div>
                        </div>
                        <div class="bg-gray-50 p-5 rounded-lg">
                            <h4 class="font-medium text-lg mb-3 text-blue-700">NameServer故障转移</h4>
                            <p class="mb-3">客户端会定期从多个NameServer获取路由信息，当某个NameServer不可用时自动切换。</p>
                            <div class="code-block p-4 rounded-md">
                                <code class="text-sm">producer.setNamesrvAddr("ns1:9876;ns2:9876");</code>
                            </div>
                        </div>
                    </div>
                </div>
                
                <div class="mt-10">
                    <h3 class="text-2xl font-semibold mb-4 text-gray-800">应用层重试策略</h3>
                    <div class="bg-gray-50 p-5 rounded-lg">
                        <div class="code-block p-4 rounded-md mb-4">
<pre class="text-sm"><code>int retries = 0;
boolean success = false;
while (!success && retries < MAX_RETRIES) {
    try {
        SendResult result = producer.send(msg);
        success = true;
    } catch (Exception e) {
        retries++;
        // 指数退避
        Thread.sleep(Math.min(1000 * (1 << retries), MAX_WAIT_TIME));
    }
}</code></pre>
                        </div>
                        <div class="grid md:grid-cols-3 gap-4">
                            <div class="bg-white p-3 rounded border border-gray-100">
                                <h4 class="font-medium mb-2 text-blue-600">业务层重试</h4>
                                <p class="text-sm text-gray-600">实现指数退避算法，设置最大重试次数</p>
                            </div>
                            <div class="bg-white p-3 rounded border border-gray-100">
                                <h4 class="font-medium mb-2 text-blue-600">本地持久化</h4>
                                <p class="text-sm text-gray-600">发送失败时将消息持久化到本地存储</p>
                            </div>
                            <div class="bg-white p-3 rounded border border-gray-100">
                                <h4 class="font-medium mb-2 text-blue-600">消息事务表</h4>
                                <p class="text-sm text-gray-600">在数据库中维护消息事务表</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Consumption Exception Section -->
        <section class="mb-16">
            <div class="bg-white rounded-xl shadow-sm p-8">
                <div class="flex items-center mb-6">
                    <div class="w-2 h-10 bg-green-600 rounded-full mr-4"></div>
                    <h2 class="text-3xl font-bold text-green-800">消费异常的处理机制</h2>
                </div>
                
                <p class="text-lg mb-8">消息消费过程中的异常处理对于保证系统的可靠性和稳定性至关重要。RocketMQ提供了完善的消费异常处理机制。</p>
                
                <div class="grid md:grid-cols-2 gap-8">
                    <div>
                        <h3 class="text-2xl font-semibold mb-4 text-gray-800">消费失败的常见原因</h3>
                        <ul class="space-y-3">
                            <li class="flex items-start">
                                <i class="fas fa-bug text-green-500 mt-1 mr-3"></i>
                                <span><strong>业务处理异常：</strong>逻辑错误、数据格式不符、外部系统异常</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-memory text-green-500 mt-1 mr-3"></i>
                                <span><strong>资源不足：</strong>内存溢出、线程池耗尽、连接池耗尽</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-hourglass-half text-green-500 mt-1 mr-3"></i>
                                <span><strong>消费超时：</strong>处理时间过长、外部系统响应慢、线程阻塞</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-lock text-green-500 mt-1 mr-3"></i>
                                <span><strong>并发冲突：</strong>数据并发修改、锁竞争、死锁</span>
                            </li>
                        </ul>
                    </div>
                    <div>
                        <h3 class="text-2xl font-semibold mb-4 text-gray-800">消费重试机制</h3>
                        <div class="bg-gray-50 p-4 rounded-lg">
                            <div class="code-block p-4 rounded-md">
<pre class="text-sm"><code>consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List&lt;MessageExt&gt; msgs, 
            ConsumeConcurrentlyContext context) {
        try {
            // 消费逻辑
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        } catch (Exception e) {
            return ConsumeConcurrentlyStatus.RECONSUME_LATER;
        }
    }
});</code></pre>
                            </div>
                        </div>
                    </div>
                </div>
                
                <div class="mt-10">
                    <h3 class="text-2xl font-semibold mb-4 text-gray-800">死信队列处理</h3>
                    <div class="grid md:grid-cols-2 gap-6">
                        <div class="bg-gray-50 p-5 rounded-lg">
                            <h4 class="font-medium text-lg mb-3 text-green-700">死信队列机制</h4>
                            <p class="mb-3">消息重试超过最大次数后进入死信队列（%DLQ%+消费组名），需要人工干预处理。</p>
                            <ul class="space-y-2 text-sm text-gray-600">
                                <li class="flex items-start">
                                    <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                    <span>设置专门的消费者消费死信队列</span>
                                </li>
                                <li class="flex items-start">
                                    <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                    <span>分析死信消息的失败原因</span>
                                </li>
                                <li class="flex items-start">
                                    <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                    <span>修复问题后重新发送消息</span>
                                </li>
                            </ul>
                        </div>
                        <div class="bg-gray-50 p-5 rounded-lg">
                            <h4 class="font-medium text-lg mb-3 text-green-700">消费幂等性保证</h4>
                            <p class="mb-3">使用消息ID或业务ID作为幂等键，确保重复消费不会导致业务错误。</p>
                            <div class="code-block p-4 rounded-md">
<pre class="text-sm"><code>String messageId = msg.getMsgId();
String consumeKey = "consumed:" + messageId;
Boolean isFirstConsume = redisTemplate.opsForValue()
    .setIfAbsent(consumeKey, "1", 7, TimeUnit.DAYS);</code></pre>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- System Recovery Section -->
        <section class="mb-16">
            <div class="bg-white rounded-xl shadow-sm p-8">
                <div class="flex items-center mb-6">
                    <div class="w-2 h-10 bg-purple-600 rounded-full mr-4"></div>
                    <h2 class="text-3xl font-bold text-purple-800">系统异常恢复的最佳实践</h2>
                </div>
                
                <p class="text-lg mb-8">在分布式消息系统中，系统级异常是不可避免的。以下是RocketMQ系统异常恢复的最佳实践。</p>
                
                <div class="grid md:grid-cols-2 gap-8">
                    <div>
                        <h3 class="text-2xl font-semibold mb-4 text-gray-800">Broker异常恢复</h3>
                        <div class="bg-gray-50 p-5 rounded-lg mb-4">
                            <h4 class="font-medium mb-3 text-purple-700">主从自动切换</h4>
                            <p class="mb-3">使用Dledger实现自动主从切换，当主Broker异常时从Broker自动升级为主Broker。</p>
                            <div class="code-block p-4 rounded-md">
<pre class="text-sm"><code>brokerClusterName=DefaultCluster
brokerName=broker-a
enableDLegerCommitLog=true
dLegerGroup=broker-a
dLegerPeers=n0-127.0.0.1:40911;n1-127.0.0.1:40912;n2-127.0.0.1:40913</code></pre>
                            </div>
                        </div>
                    </div>
                    <div>
                        <h3 class="text-2xl font-semibold mb-4 text-gray-800">消费进度恢复</h3>
                        <div class="bg-gray-50 p-5 rounded-lg">
                            <h4 class="font-medium mb-3 text-purple-700">消费位点管理</h4>
                            <ul class="space-y-2 text-gray-600">
                                <li class="flex items-start">
                                    <i class="fas fa-check-circle text-purple-500 mt-1 mr-2"></i>
                                    <span>消费位点默认存储在Broker上</span>
                                </li>
                                <li class="flex items-start">
                                    <i class="fas fa-check-circle text-purple-500 mt-1 mr-2"></i>
                                    <span>定期将消费位点持久化到磁盘</span>
                                </li>
                                <li class="flex items-start">
                                    <i class="fas fa-check-circle text-purple-500 mt-1 mr-2"></i>
                                    <span>支持手动调整消费位点</span>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Visualization Section -->
        <section class="mb-16">
            <div class="bg-white rounded-xl shadow-sm p-8">
                <h2 class="text-3xl font-bold mb-8 text-blue-800">RocketMQ异常处理流程可视化</h2>
                
                <div class="mermaid">
                    graph TD
                        A[消息发送] -->|成功| B[正常处理]
                        A -->|失败| C{重试次数<br>是否达到上限?}
                        C -->|否| D[自动重试]
                        C -->|是| E[进入死信队列]
                        D --> A
                        E --> F[人工处理]
                        F -->|修复后| A
                        
                        G[消息消费] -->|成功| H[确认消费]
                        G -->|失败| I{重试次数<br>是否达到上限?}
                        I -->|否| J[进入重试队列]
                        I -->|是| K[进入死信队列]
                        J -->|延迟重试| G
                        K --> L[人工处理]
                        L -->|修复后| G
                </div>
            </div>
        </section>
    </main>

    <!-- Footer -->
    <footer class="footer text-white py-8">
        <div class="container mx-auto max-w-5xl px-4 md:px-0">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <h3 class="text-xl font-semibold">技术小馆</h3>
                </div>
                <div>
                    <a href="http://www.yuque.com/jtostring" class="hover:text-blue-300 transition-colors">
                        <i class="fas fa-link mr-2"></i>http://www.yuque.com/jtostring
                    </a>
                </div>
            </div>
        </div>
    </footer>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
    </script>
</body>
</html>